package pl;

import javacard.framework.JCSystem;
import javacard.framework.Util;

/* ISO7816-4 */
public class FileParameterParser {

	public static final byte DF_FDB = (byte)0x38;
	public static final byte EF_FDB = (byte)0x01;
	
	/* tags */
	public PrimitiveBERTag FILESIZE_TAG;	
	public PrimitiveBERTag FDB_TAG;
	public PrimitiveBERTag FID_TAG;
	public PrimitiveBERTag DFNAME_TAG; 
	public PrimitiveBERTag ACCESS_TAG; 
	public ConstructedBERTag FCP_TAG;

	/* tlv's */
	public PrimitiveBERTLV dfnameTlv;
	public PrimitiveBERTLV fidTlv;
	public PrimitiveBERTLV fdbTlv;
	public PrimitiveBERTLV filesizeTlv;
	public PrimitiveBERTLV accessTlv;
	
	public ConstructedBERTLV fcpTemplate;
	
	private byte[] tempBuffer;
	
	public FileParameterParser()
	{
		FILESIZE_TAG = (PrimitiveBERTag) BERTag.getInstance(new byte[]{(byte)0x81}, (short)0);
		DFNAME_TAG = (PrimitiveBERTag) BERTag.getInstance(new byte[]{(byte)0x84}, (short)0);
		FDB_TAG = (PrimitiveBERTag) BERTag.getInstance(new byte[]{(byte)0x82}, (short)0);
		FID_TAG = (PrimitiveBERTag) BERTag.getInstance(new byte[]{(byte)0x83}, (short)0);
		ACCESS_TAG  = (PrimitiveBERTag) BERTag.getInstance(new byte[]{(byte)0x8C}, (short)0);
		
		FCP_TAG = (ConstructedBERTag) BERTag.getInstance(new byte[]{(byte)0x6F}, (short)0);
		
		filesizeTlv = new PrimitiveBERTLV((short)2);
		fdbTlv = new PrimitiveBERTLV((short)1);
		fidTlv = new PrimitiveBERTLV((short)2);
		dfnameTlv = new PrimitiveBERTLV((short)16);
		accessTlv = new PrimitiveBERTLV((short)3);	
		
		// Constructed TLV -> 10 tags capacity
		fcpTemplate = new ConstructedBERTLV((short) 6);
		tempBuffer = JCSystem.makeTransientByteArray((short) 3, JCSystem.CLEAR_ON_DESELECT);
	}
	
	public void constructFciForDf(byte[] outBuf, byte[] fid, byte[] dfname, byte[] access)
	{		
		short offset = 2;
		
		// fdb
		fdbTlv.init(FDB_TAG, new byte[] {DF_FDB}, (short)0, (short)1);
		fdbTlv.toBytes(outBuf, offset);
		
		offset += fdbTlv.size();
		// fid
		fidTlv.init(FID_TAG, fid, (short)0, (short)2);
		fidTlv.toBytes(outBuf, offset);

		offset += fidTlv.size();
		
		//------------------------------------------------//
		// name
		dfnameTlv = new PrimitiveBERTLV((short) dfname.length);
		dfnameTlv.init(DFNAME_TAG, dfname, (short)0, (short) dfname.length);
		dfnameTlv.toBytes(outBuf, offset);
		
		offset += dfnameTlv.size();
		
		// access
		accessTlv = new PrimitiveBERTLV((short) access.length);
		accessTlv.init(ACCESS_TAG, access, (short)0, (short)access.length);
		accessTlv.toBytes(outBuf, offset);
		
		offset += accessTlv.size();
		
		// tag
		FCP_TAG.toBytes(outBuf, (short)0);		
		// length
		outBuf[1] = (byte) (outBuf.length - 2);
	}

	public void constructFciforEf(byte[] outBuf, byte[] fid, short size, byte[] access)
	{
		short offset = 2;
		
		// file size 
		tempBuffer = JCSystem.makeTransientByteArray((short) 2, JCSystem.CLEAR_ON_DESELECT);	
		tempBuffer[0] = MediatorFE.shortOnByteArray(size)[1];
		tempBuffer[1] = MediatorFE.shortOnByteArray(size)[0];
		filesizeTlv.init(FILESIZE_TAG, tempBuffer, (short)0, (short)2);
		filesizeTlv.toBytes(outBuf, offset);
		offset += filesizeTlv.size();
		
		// fdb
		fdbTlv.init(FDB_TAG, new byte[] {EF_FDB}, (short)0, (short)1);
		fdbTlv.toBytes(outBuf, offset);
		offset += fdbTlv.size();
		
		// fid
		fidTlv.init(FID_TAG, fid, (short)0, (short)2);
		fidTlv.toBytes(outBuf, offset);
		offset += fidTlv.size();

		// access
		accessTlv = new PrimitiveBERTLV((short) access.length);
		accessTlv.init(ACCESS_TAG, access, (short)0, (short)access.length);
		accessTlv.toBytes(outBuf, offset);
		
		offset += accessTlv.size();
		
		// tag
		FCP_TAG.toBytes(outBuf, (short)0);		
		// length
		outBuf[1] = (byte) (outBuf.length - 2);
	}
	
	public boolean parseFciTemplate(byte[] fcp)
	{
		if (BERTLV.verifyFormat(fcp, (short)0, (short) fcp.length))
		{
			fcpTemplate.init(fcp, MediatorFE.O, (short)fcp.length);
			
			// fid
			fidTlv = (PrimitiveBERTLV)fcpTemplate.find(FID_TAG);
			if (fidTlv == null) return false;

			// mandatory - fdbTlv
			fdbTlv = (PrimitiveBERTLV)fcpTemplate.find(FDB_TAG);
			if (fdbTlv == null) return false;
			
			fdbTlv.toBytes(tempBuffer, (short)0);
			
			if (tempBuffer[2] == 0x38)
			{
				// mandatory for DF
				dfnameTlv = (PrimitiveBERTLV)fcpTemplate.find(DFNAME_TAG);
				if (filesizeTlv == null) return false;
			}
			else if (tempBuffer[2] == 0x01)
			{
				// mandatory for EF
				filesizeTlv = (PrimitiveBERTLV)fcpTemplate.find(FILESIZE_TAG);
				if (filesizeTlv == null) return false;
			}
			else
			{
				return false;
			}
			
			// access conditions
			accessTlv = (PrimitiveBERTLV)fcpTemplate.find(ACCESS_TAG);
			if (accessTlv == null) return false;
			
			return true;
		}
		else
			return false;

	}

	public boolean parseFciTemplate3(byte[] fcp)
	{
		if (BERTLV.verifyFormat(fcp, (short)0, (short) fcp.length))
		{
			for (short i = 0; i < (short)fcp.length; i++)
			{
				switch  (fcp[i])
				{
					case (byte)0x81:
						
						break;
					
					case (byte)0x82:
						break;
				}
			}
			
			fcpTemplate.init(fcp, MediatorFE.O, (short)fcp.length);
			
			// fid
			fidTlv = (PrimitiveBERTLV)fcpTemplate.find(FID_TAG);
			if (fidTlv == null) return false;

			// mandatory - fdbTlv
			fdbTlv = (PrimitiveBERTLV)fcpTemplate.find(FDB_TAG);
			if (fdbTlv == null) return false;
			
			fdbTlv.toBytes(tempBuffer, (short)0);
			
			if (tempBuffer[2] == 0x38)
			{
				// mandatory for DF
				dfnameTlv = (PrimitiveBERTLV)fcpTemplate.find(DFNAME_TAG);
				if (filesizeTlv == null) return false;
			}
			else if (tempBuffer[2] == 0x01)
			{
				// mandatory for EF
				filesizeTlv = (PrimitiveBERTLV)fcpTemplate.find(FILESIZE_TAG);
				if (filesizeTlv == null) return false;
			}
			else
			{
				return false;
			}
			
			// access conditions
			accessTlv = (PrimitiveBERTLV)fcpTemplate.find(ACCESS_TAG);
			if (accessTlv == null) return false;
			
			return true;
		}
		else
			return false;

	}

	
	private BERTLV init3(BERTag tag, byte[] array)
	{
		short length = 0;
		
		tempBuffer = JCSystem.makeTransientByteArray((short) 1, JCSystem.CLEAR_ON_DESELECT);
		
		tag.toBytes(tempBuffer, (short)0);
		
		for (short i = 0; i < (short)array.length; i++)
		{
			if (array[i] == tempBuffer[0]) 
			{
				length = (short) (array[(short)(i + 1)] + 2);
				
				tempBuffer = JCSystem.makeTransientByteArray(length, JCSystem.CLEAR_ON_DESELECT);
				
				Util.arrayCopy(array, i, tempBuffer, (short)0, length);
				
				return BERTLV.getInstance(tempBuffer, (short)0, (short)tempBuffer.length);
			}
		}

		return null;
	}
}
